import os
import time
import json
import logging
import uuid
from flask import Flask, render_template, request, jsonify, session
# from flask_cors import CORS
import dashscope
from dashscope import MultiModalConversation, Application
import oss2

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# 初始化Flask应用
app = Flask(__name__, static_folder='static')
# CORS(app)  # 启用CORS支持跨域请求
app.config['UPLOAD_FOLDER'] = 'uploads'
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024  # 限制文件大小为16MB
app.config['SECRET_KEY'] = os.urandom(24)  # 用于Flask session

# 确保上传目录存在
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)

# 设置DashScope API Key
dashscope.api_key = os.environ.get("DASHSCOPE_API_KEY")

# OSS配置
OSS_BUCKET_NAME = "llm-xinqi-public-bucket"
OSS_DIRECTORY = "nongxian/audio/"
OSS_ACCESS_KEY_ID = os.environ.get('OSS_ACCESS_KEY_ID')
OSS_ACCESS_KEY_SECRET = os.environ.get('OSS_ACCESS_KEY_SECRET')
OSS_ENDPOINT = 'https://oss-cn-hangzhou.aliyuncs.com'
OSS_ENDPOINT_WITHOUT_HTTP = 'oss-cn-hangzhou.aliyuncs.com'

def secure_filename_with_chinese(filename):
    """安全处理文件名，保留中文字符"""
    # 获取文件扩展名
    _, ext = os.path.splitext(filename)
    # 生成随机文件名
    random_filename = str(uuid.uuid4())
    return random_filename + ext

def upload_to_oss(file_path, oss_directory):
    """上传文件到OSS并返回文件URL"""
    auth = oss2.Auth(OSS_ACCESS_KEY_ID, OSS_ACCESS_KEY_SECRET)
    bucket = oss2.Bucket(auth, OSS_ENDPOINT, OSS_BUCKET_NAME)

    try:
        # 获取文件名
        file_name = os.path.basename(file_path)
        # 构建OSS上的完整路径
        oss_object_name = os.path.join(oss_directory, file_name)

        # 上传文件
        with open(file_path, 'rb') as fileobj:
            bucket.put_object(oss_object_name, fileobj)

        # 构建文件URL
        file_url = f"https://{OSS_BUCKET_NAME}.{OSS_ENDPOINT_WITHOUT_HTTP}/{oss_object_name}"
        logger.info(f"Successfully uploaded: {file_path} -> {file_url}")

        return file_url
    except Exception as e:
        logger.error(f"Failed to upload: {file_path}, Error: {e}")
        return None

@app.route('/')
def index():
    """渲染主页"""
    return render_template('index.html')

@app.route('/upload_audio', methods=['POST'])
def upload_audio():
    """接收音频文件并上传到OSS"""
    if 'audio' not in request.files:
        return jsonify({"error": "没有音频文件"}), 400
    
    file = request.files['audio']
    if file.filename == '':
        return jsonify({"error": "未选择文件"}), 400
    
    # 检查文件大小，避免空文件
    file_content = file.read()
    file_size = len(file_content)
    
    # 提高阈值到1KB
    if file_size < 1000:  # 小于1KB可能是无效音频
        return jsonify({"error": "音频文件为空或太小，无法处理"}), 400
    
    # 重置文件指针
    file.seek(0)
    
    # 安全处理文件名并保存
    filename = secure_filename_with_chinese(file.filename)
    file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
    file.save(file_path)
    
    # 添加日志
    logger.info(f"保存音频文件: {file_path}, 大小: {file_size} 字节")
    
    # 上传到OSS
    file_url = upload_to_oss(file_path, OSS_DIRECTORY)
    
    # 删除本地文件
    os.remove(file_path)
    
    if file_url:
        return jsonify({"success": True, "audio_url": file_url})
    else:
        return jsonify({"error": "音频上传到OSS失败"}), 500

@app.route('/convert_audio', methods=['POST'])
def convert_audio():
    """将语音转换为文本"""
    data = request.json
    audio_url = data.get('audio_url')
    
    if not audio_url:
        return jsonify({"error": "缺少音频URL"}), 400
    
    try:
        # 调用通义千问Audio模型进行语音转文本
        start_time = time.time()
        messages = [
            {
                "role": "user",
                "content": [
                    {"audio": audio_url}
                    # {"text": "你需要只输出转换后文本"}
                ]
            }
        ]
        
        response = MultiModalConversation.call(
            # model="qwen-audio-turbo-latest",
            model="qwen-audio-asr-latest",
            messages=messages,
            result_format="message"
        )
        
        elapsed_time = time.time() - start_time
        
        if response.status_code == 200:
            # 从响应中提取文本内容
            text_content = response.output.choices[0].message.content[0].get("text", "")
            
            return jsonify({
                "success": True,
                "text": text_content,
                "elapsed_time": f"{elapsed_time:.2f}"
            })
        else:
            return jsonify({
                "error": f"语音转换失败: {response.message}",
                "status_code": response.status_code
            }), 500
    
    except Exception as e:
        logger.error(f"语音转换错误: {str(e)}")
        return jsonify({"error": f"语音转换错误: {str(e)}"}), 500

@app.route('/get_menu', methods=['POST'])
def get_menu():
    """根据文本查询相关菜单"""
    data = request.json
    query_text = data.get('text')
    session_id = data.get('session_id')
    new_conversation = data.get('new_conversation', False)
    
    if not query_text:
        return jsonify({"error": "查询文本为空"}), 400
    
    # 简单关键词匹配进行演示
    # account_keywords = ['账户', '账号', '查询账户', '我的账户']
    # if any(keyword in query_text for keyword in account_keywords):
    #     # 返回账户查询的菜单信息，使用mPaaS离线包URL格式
    #     return jsonify({
    #         "success": True,
    #         "needMore": False,
    #         "result": {
    #             "menuName": "个人账户查询",
    #             "menuUrl": "mpaas://com.alipay.mobile.nebulaappproxy",
    #             "params": {
    #                 "appId": "20230923000039488915",
    #                 "clientVersion": "10.2.90",
    #                 "nebulaParam": json.dumps({
    #                     "pageUrl": "https://lazyyou.xyz/account-query",
    #                     "showOptionMenu": "NO"
    #                 })
    #             },
    #             "description": "点击跳转到保单查询页面，查询您的保单信息。",
    #             "menuDescription": "查看您的所有保单和账户信息，包括保单号、生效日期、保障期限等。"
    #         },
    #         "session_id": session_id or str(uuid.uuid4()),
    #         "elapsed_time": "0.12"
    #     })
    #
    # # 追加保费关键词匹配
    # payment_keywords = ['追加保费', '追加', '缴费']
    # if any(keyword in query_text for keyword in payment_keywords):
    #     # 返回追加保费的菜单信息，使用原生功能调用格式
    #     return jsonify({
    #         "success": True,
    #         "needMore": False,
    #         "result": {
    #             "menuName": "追加保费",
    #             "menuUrl": "native://openPayment",
    #             "params": {
    #                 "type": "additional",
    #                 "source": "assistant"
    #             },
    #             "description": "点击进入追加保费页面，快速完成保费缴纳。",
    #             "menuDescription": "办理追加保费业务，快速完成保费缴纳。"
    #         },
    #         "session_id": session_id or str(uuid.uuid4()),
    #         "elapsed_time": "0.14"
    #     })
    
    # # 保单贷款关键词匹配
    # loan_keywords = ['保单贷款', '贷款', '借款', '保单借款']
    # if any(keyword in query_text for keyword in loan_keywords):
    #     # 返回保单贷款的菜单信息，使用URL方式
    #     return jsonify({
    #         "success": True,
    #         "needMore": False,
    #         "result": {
    #             "menuName": "保单贷款",
    #             "menuUrl": "https://lazyyoun.xyz/policy-loan",
    #             "description": "点击进入保单贷款页面，快速获取资金。",
    #             "menuDescription": "使用您的保单进行贷款，快速获取资金。"
    #         },
    #         "session_id": session_id or str(uuid.uuid4()),
    #         "elapsed_time": "0.15"
    #     })
    
    # 对于其他查询，使用通义千问应用
    try:
        # 调用Application API进行意图识别
        start_time = time.time()
        
        # 构建请求参数
        call_params = {
            'api_key': os.getenv("DASHSCOPE_API_KEY"),
            'app_id': os.getenv("DEMO_APP_ID"),
            'prompt': f"请根据用户的请求'{query_text}'分析意图并给出匹配的功能菜单。",
            'response_format': {'type': 'json_object'}
        }
        
        # 如果不是新对话且有session_id，则添加到请求中
        if not new_conversation and session_id:
            call_params['session_id'] = session_id
        
        # 调用API
        response = Application.call(**call_params)
        
        elapsed_time = time.time() - start_time
        
        if response.status_code == 200:
            # 解析响应
            text_content = response.output.get("text", "{}")
            session_id = response.output.get("session_id", "")
            
            try:
                # 将JSON字符串转换为Python对象
                result = json.loads(text_content)
                
                # 检查是否需要更多信息
                need_more = result.get("needMore", False)
                
                if need_more:
                    # 需要更多信息，返回消息提示用户
                    return jsonify({
                        "success": True,
                        "needMore": True,
                        "message": result.get("message", "请提供更详细的信息，以便我更好地帮助您"),
                        "session_id": session_id,
                        "elapsed_time": f"{elapsed_time:.2f}"
                    })
                else:
                    # 不需要更多信息，返回菜单
                    if "menuUrl" not in result:
                        result["menuUrl"] = "#"
                        result["menuName"] = "未找到匹配菜单"
                    
                    # 如果没有description字段，添加一个默认描述
                    if "description" not in result:
                        result["description"] = "点击下方按钮访问功能"
                    
                    return jsonify({
                        "success": True,
                        "needMore": False,
                        "result": result,
                        "session_id": session_id,
                        "elapsed_time": f"{elapsed_time:.2f}"
                    })
            except json.JSONDecodeError:
                return jsonify({
                    "error": "解析结果失败，返回的不是有效的JSON格式"
                }), 500
        else:
            return jsonify({
                "error": f"查询失败: {response.message}", 
                "status_code": response.status_code
            }), 500
    
    except Exception as e:
        logger.error(f"菜单查询错误: {str(e)}")
        return jsonify({"error": f"菜单查询错误: {str(e)}"}), 500

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5003, debug=True) 